#include "Window.h"

namespace Lame3d
{
	Window::Window(const std::string &n, const Point2d &s, const Point2d &loc, UILayout *l)
			: name(n), size(s), location(loc), resizable(false), layout(l), opacity(0), deleting(false)
	{
		if(layout == NULL) {
			layout = new AbsoluteLayout();
		}
		layout->ParentSize(size);
	}
	
	Window::~Window()
	{
		delete layout;
		std::map<std::string, UIElement*>::iterator it;
		for(it = elements.begin(); it != elements.end(); ++it) {
			delete it->second;
		}
	}
	
	const std::string& Window::Name() const
	{
		return name;
	}
	
	const Point2d& Window::Size() const
	{
		return size;
	}
	
	void Window::Size(const Point2d &s)
	{
		size = s;
		layout->ParentSize(size);
		layout->Pack();
	}
	
	const Point2d& Window::Location() const
	{
		return location;
	}
	
	Point2d& Window::Location()
	{
		return location;
	}
	
	bool Window::Contains(const Point2d &pt) const
	{
		Point2d diff = pt;
		diff -= location;
		//printf("diff: %f, %f\n", diff[0], diff[1]);
		if((diff[0] >= 0) && (diff[0] <= size[0])
				&& (diff[1] <= 0) && (diff[1] >= -size[1])) {
			return true;
		}
		return false;
	}
	
	UIElement* Window::ElementAt(const Point2d &pt)
	{
		Point2d localCoords(
			pt[0]-location[0],
			location[1]-pt[1] );
		std::map<std::string, UIElement*>::iterator it;
		for(it = elements.begin(); it != elements.end(); ++it) {
			Point2d diff = localCoords;
			diff -= it->second->Location();
			const Point2d &size = it->second->Size();
			printf("%f\n", diff[1]);
			if((diff[0] >= 0) && (diff[0] <= size[0])
					&& (diff[1] >= 0) && (diff[1] <= size[1])) {
				return it->second;
			}
		}
		
		return NULL;
	}
	
	bool Window::Resizable() const
	{
		return resizable;
	}
	
	void Window::Resizable(bool b)
	{
		resizable = b;
	}
	
	void Window::Add(UILabel *l, UILayoutProperties *layoutProps)
	{
		labels.push_back(l);
		std::map<std::string, UIElement*>::iterator it;
		it = elements.find(l->Name());
		if(it != elements.end()) {
			throw "Name conflict when adding UILabel.";
		}
		elements[l->Name()] = l;
		layout->AddElement(l, layoutProps);
	}
	
	std::list<UILabel*>::const_iterator Window::LabelsBegin() const
	{
		return labels.begin();
	}
	
	std::list<UILabel*>::const_iterator Window::LabelsEnd() const
	{
		return labels.end();
	}
	
	void Window::Add(UIButton *b, UILayoutProperties *layoutProps)
	{
		buttons.push_back(b);
		std::map<std::string, UIElement*>::iterator it;
		it = elements.find(b->Name());
		if(it != elements.end()) {
			throw "Name conflict when adding UIButton.";
		}
		elements[b->Name()] = b;
		layout->AddElement(b, layoutProps);
	}
	
	std::list<UIButton*>::const_iterator Window::ButtonsBegin() const
	{
		return buttons.begin();
	}
	
	std::list<UIButton*>::const_iterator Window::ButtonsEnd() const
	{
		return buttons.end();
	}
	
	void Window::Add(UITextEntry *b, UILayoutProperties *layoutProps)
	{
		entries.push_back(b);
		std::map<std::string, UIElement*>::iterator it;
		it = elements.find(b->Name());
		if(it != elements.end()) {
			throw "Name conflict when adding UITextEntry.";
		}
		elements[b->Name()] = b;
		layout->AddElement(b, layoutProps);
	}
	
	std::list<UITextEntry*>::const_iterator Window::TextEntriesBegin() const
	{
		return entries.begin();
	}
	
	std::list<UITextEntry*>::const_iterator Window::TextEntriesEnd() const
	{
		return entries.end();
	}
	
	template<typename T>
	bool removeType(UIElement *e, std::list<T*> &list)
	{
		T *t = static_cast<T*>(e);
		typename std::list<T*>::iterator it;
		for(it = list.begin(); it != list.end(); ++it) {
			if(*it == t) {
				list.erase(it);
				return true;
			}
		}
		return false;
	}
	
	void Window::Remove(const std::string &n)
	{
		// remove from layout manager
		UIElement *e = elements[n];
		layout->RemoveElement(e);
		elements.erase(n);
		
		// try label remove	
		if(removeType<UILabel>(e, labels)) {
			return;
		}
		
		// try button remove
		if(removeType<UIButton>(e, buttons)) {
			return;
		}
		
		// try textentry remove
		if(removeType<UITextEntry>(e, entries)) {
			return;
		}
		
		// try other removes...
	}
	
	float Window::Opacity() const
	{
		return opacity;
	}
	
	void Window::Opacity(float f)
	{
		opacity = f;
	}
	
	bool Window::Deleting() const
	{
		return deleting;
	}
	
	void Window::Delete()
	{
		deleting = true;
	}
}

// eof //
